﻿using System;
using System.Collections.Generic;
using System.Web;
using System.Text;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Newtonsoft.Json;
using System.Collections;

namespace WxPayAPI
{
    /// <summary>
    /// 回调处理基类
    /// 主要负责接收微信支付后台发送过来的数据，对数据进行签名验证
    /// 子类在此类基础上进行派生并重写自己的回调处理过程
    /// </summary>
    public class Notify
    {
        public HttpContext page { get; set; }
        public Notify(HttpContext page)
        {
            this.page = page;
        }

        /// <summary>
        /// 接收从微信支付后台发送过来的数据并验证签名
        /// </summary>
        /// <returns>微信支付后台返回的数据</returns>
        public  WxPayData GetNotifyData()
        {
            Log.Debug(this.GetType().ToString(), "step_00_00");
            //接收从微信后台POST过来的数据
            //var rt;
            var builder = Xx();

            //System.IO.Stream s = page.Request.Body;
            //int count = 0;
            //byte[] buffer = new byte[1024];
            //StringBuilder builder = new StringBuilder();
            //Log.Debug(this.GetType().ToString(), "step_00_01");
            //try
            //{
            //    while ((count = s.Read(buffer, 0, 1024)) > 0)
            //    {
            //        builder.Append(Encoding.UTF8.GetString(buffer, 0, count));
            //    }
            //    s.Flush();
            //    s.Close();
            //    s.Dispose();
            //}
            //catch (Exception ex)
            //{
            //    Log.Debug(this.GetType().ToString(), ex.Message);
            //    throw;
            //}

            Log.Debug(this.GetType().ToString(), "step_00_02");

            Log.Debug(this.GetType().ToString(), "Receive data from WeChat : " + builder.Result);
            
            Hashtable hb = JsonConvert.DeserializeObject<Hashtable>(builder.Result);
            Log.Debug(this.GetType().ToString(), "Receive data from WeChat : " + hb);

            //转换数据格式并验证签名
            WxPayData data = new WxPayData();
            try
            {
                Log.Debug(this.GetType().ToString(), "Receive data from WeChat : " + hb["resource"]);
                Hashtable hbResource = JsonConvert.DeserializeObject<Hashtable>(hb["resource"].ToString());
                Log.Debug(this.GetType().ToString(), "Receive data from WeChat : " + hbResource["ciphertext"]);
                //解密
                string plaintext= data.AesGcmDecrypt(hbResource["associated_data"].ToString(), hbResource["nonce"].ToString(), hbResource["ciphertext"].ToString());
                Log.Debug(this.GetType().ToString(), "plaintext:" + plaintext);
                //解析plaintext
                Hashtable hb1 = JsonConvert.DeserializeObject<Hashtable>(plaintext);
                data.SetValue("mchid", hb1["mchid"]); //商户号
                data.SetValue("out_trade_no", hb1["out_trade_no"]); //商户订单号
                data.SetValue("transaction_id", hb1["transaction_id"]); //微信支付订单号
                data.SetValue("trade_type", hb1["trade_type"]); //交易类型
                data.SetValue("trade_state_desc", hb1["trade_state_desc"]); //交易状态
            }
            catch (WxPayException ex)
            {
                //若签名错误，则立即返回结果给微信支付后台
                WxPayData res = new WxPayData();
                res.SetValue("return_code", "FAIL");
                res.SetValue("return_msg", ex.Message);
                Log.Error(this.GetType().ToString(), "Sign check error : " + res.ToXml());
                page.Response.WriteAsync(res.ToXml());
            }

            Log.Debug(this.GetType().ToString(), "Check sign success");
            return data;
        }

        public async System.Threading.Tasks.Task<string> Xx()
        {
            using (var s = new System.IO.StreamReader(page.Request.Body, System.Text.Encoding.UTF8))
            {
                s.BaseStream.Seek(0, System.IO.SeekOrigin.Begin);
                var rt = await s.ReadToEndAsync();
                s.BaseStream.Close();
                s.BaseStream.Dispose();
                return rt;
            }
        }
        

        //派生类需要重写这个方法，进行不同的回调处理
        public virtual void ProcessNotify()
        {

        }
    }
}